/** Fichier implémentant une classe représentant les matrices du groupe @f$O( 3,
 * R )@f$.
 *
 * Ce fichier contient l'implémentation de la classe MatriceO3.
 *
 * @file MatriceO3.cpp
 * @author Johan "Solo" Luisier
 *
 * @date 24 Juin 2011
 */
#include "MatriceO3.hpp"

#include "Utils/Erreur.hpp"

#include <cmath>
#include <iostream>

using namespace std;

/** Constructeur par défaut, construit une matrice scalaire.
 *
 * Constructeur permettant de créer une matrice scalaire. La version
 * par défaut crée la matrice identité
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +/- 1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide (matrice non inversible).
 *
 * @param[in] scalaire nombre à mettre sur la diagonale.
 */
MatriceO3::MatriceO3(const double& scalaire)
    : MatriceGL3( scalaire )
{
    this -> operator*=( 1. / abs( pow( determinant(), 1. / 3. ) ) );
    verifie();
}

/**
 * Constructeur initialisant les colonnes de la matrices avec les
 * images des trois vecteurs de base, lorsque la matrice est vue comme
 * une rotation ou une roto-inversion.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +/- 1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] x image de Ox.
 * @param[in] y image de Oy.
 * @param[in] z image de Oz.
 */
MatriceO3::MatriceO3(const Vecteur& x, const Vecteur& y, const Vecteur& z)
    : MatriceGL3( x, y, z )
{
    this -> operator*=( 1. / abs( pow( determinant(), 1. / 3. ) ) );
    verifie();
}

/**
 * Constructeur de copie, permettant de dupliquer une MatriceO3.
 *
 * Ici pas besoin de vérifier si la matrice à copier a bien un
 * déterminant égal à +/- 1 : c'est déjà une Matrice03.
 *
 * @param[in] mat objet à copier.
 */
MatriceO3::MatriceO3(const MatriceO3& mat)
    : MatriceGL3( mat )
{}

/**
 * Constructeur permettant de promouvoir une MatriceGL3 en MatriceO3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +/- 1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceO3::MatriceO3(const MatriceGL3& mat)
    : MatriceGL3( mat )
{
    this -> operator*=( 1. / abs( pow( determinant(), 1. / 3. ) ) );
    verifie();
}

/**
 * Constructeur permettant de promouvoir une Matrice3x3 en MatriceO3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +/- 1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceO3::MatriceO3(const Matrice3x3& mat)
    : MatriceGL3( mat )
{
    verifie();
}

/**
 * Le destructeur n'a rien de spécial à faire.
 */
MatriceO3::~MatriceO3()
{}

/**
 * Méthode d'affectation, permettant de copier une instance.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +/- 1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à copier.
 *
 * @return référence sur l'instance courante modifiée.
 */
MatriceO3& MatriceO3::operator=(const Matrice3x3& mat)
{
    this -> Matrice3x3::operator=( mat );

    verifie();

    return *this;
}

/** Méthode qui vérifie que la matrice fait bien partie du groupe @f$ O \left(
* 3 \right) @f$.
 *
 * Méthode qui vérifie que le déterminant de la matrice est +/- 1. Une
 * exception de type Erreur est lancée dans le cas contraire.
 *
 * @throw Erreur si le déterminant n'est pas 1 ou -1.
 */
void MatriceO3::verifie() const
{
    if ( abs( abs( determinant() ) - 1  ) >  1.e-7 )
    {
        cerr << "MatriceO3::verifie() Déterminant différent de +/- 1 : "
             << determinant() << endl;
        cerr << *this << endl;
        throw Erreur( false, 0, "Déterminant différent de +/- 1", "MatriceO3" );
    }
}
